package com.secure.util;

import cn.hutool.core.collection.CollectionUtil;

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 签名工具类
 * <p>
 * hutool库SecureUtil有各种加解密算法工具方法
 *
 * @author duchao
 */
public class SignatureUtil {

    /**
     * 算法
     */
    private static final String ENCRYPT_DECRYPT_ALGORITHM = "RSA";

    /**
     * 签名算法
     */
    private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

    /**
     * RSA密钥长度：1024、2048、3072、7680、15360
     */
    private static final List<Integer> KEY_SIZE_LIST = CollectionUtil.toList(1024, 2048, 3072, 7680, 15360);

    /**
     * 生成秘钥对
     */
    public static KeyPair getKeyPair() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ENCRYPT_DECRYPT_ALGORITHM);
        keyPairGenerator.initialize(KEY_SIZE_LIST.get(0));
        return keyPairGenerator.generateKeyPair();
    }

    /**
     * 生成秘钥对
     *
     * @param keySize RSA密钥长度：1024、2048、3072、7680、15360
     */
    public static KeyPair generateKeyPair(Integer keySize) throws Exception {
        if (!KEY_SIZE_LIST.contains(keySize)) {
            throw new IllegalArgumentException(String.format("%s加密算法的密钥长度只能为%s", ENCRYPT_DECRYPT_ALGORITHM, KEY_SIZE_LIST.stream().map(String::valueOf).collect(Collectors.joining("、"))));
        }
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ENCRYPT_DECRYPT_ALGORITHM);
        keyPairGenerator.initialize(keySize);
        return keyPairGenerator.generateKeyPair();
    }

    /**
     * 生成公钥(Base64编码)
     * <p>
     * 密钥长度为要求最低长度
     */
    public static String getPublicKey(KeyPair keyPair) {
        PublicKey publicKey = keyPair.getPublic();
        byte[] keyBytes = publicKey.getEncoded();
        return Base64.getEncoder().encodeToString(keyBytes);
    }

    /**
     * 生成私钥(Base64编码)
     * <p>
     * 密钥长度为要求最低长度
     */
    public static String getPrivateKey(KeyPair keyPair) {
        PrivateKey privateKey = keyPair.getPrivate();
        byte[] keyBytes = privateKey.getEncoded();
        return Base64.getEncoder().encodeToString(keyBytes);
    }

    /**
     * 签名
     *
     * @param plainText  明文
     * @param privateKey 私钥(Base64编码)
     */
    public static String sign(String plainText, String privateKey) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(string2PrivateKey(privateKey));
        signature.update(plainText.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(signature.sign());
    }

    /**
     * 验签
     *
     * @param plainText     明文
     * @param signatureText 签名(Base64编码)
     * @param publicKey     公钥(Base64编码)
     * @return
     * @throws Exception
     */
    public static boolean verify(String plainText, String signatureText, String publicKey) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(string2PublicKey(publicKey));
        signature.update(plainText.getBytes(StandardCharsets.UTF_8));
        return signature.verify(Base64.getDecoder().decode(signatureText));
    }

    /**
     * Base64编码后的公钥z转换成PublicKey对象
     *
     * @param publicKeyStr 公钥(Base64编码)
     */
    private static PublicKey string2PublicKey(String publicKeyStr) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ENCRYPT_DECRYPT_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 将Base64编码后的私钥转换成PrivateKey对象
     *
     * @param privateKeyStr 私钥(Base64编码)
     */
    private static PrivateKey string2PrivateKey(String privateKeyStr) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(privateKeyStr);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ENCRYPT_DECRYPT_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

    public static void main(String[] args) throws Exception {

//        String publicKey = KeyConstant.RSA_DEFAULT_PUBLIC_KEY;
//        String privateKey = KeyConstant.RSA_DEFAULT_PRIVATE_KEY;
//        log.info("接收方的公钥：{}", publicKey);
//        log.info("接收方的私钥：{}", privateKey);
//        String plainText = "小明";
//        log.info("明文：{}", plainText);
//        String encode = encryptByPublicKey(plainText, publicKey);
//        log.info("公钥加密：{}", encode);
//        String decode = decryptByPrivateKey(encode, privateKey);
//        log.info("私钥解密：{}", decode);

        //String plainText = "eyJpZCI6MSwibmFtZSI6IuWwj+aYjiIsImRldGFpbCI6bnVsbH0xMjM0NTY=";
//        String plainText = "id=1&name=小明";
//        System.out.println("请求明文字符串：" + plainText);
//        String signatureText = sign(plainText, KeyConstant.SIGNATURE_DEFAULT_PRIVATE_KEY);
//        System.out.println("签名字符串：" + signatureText);

//        KeyPair keyPair2 = getKeyPair();
//        String publicKey2 = getPublicKey(keyPair2);
//        String privateKey2 = getPrivateKey(keyPair2);
//        log.info("发送方的公钥：{}", publicKey2);
//        log.info("发送方的私钥：{}", privateKey2);
//        String sign = sign(plainText, privateKey2);
//        log.info("私钥签名：{}", sign);
//        boolean verify = verify(decode, sign, publicKey2);
//        log.info("公钥验签：{}", verify);

        List<String> nameList = new ArrayList<>();
        nameList.add("id");
        nameList.add("name");
        nameList.add("signature");
        System.out.println(nameList);

    }


}